Skip Headers

Oracle® XML Developer's Kit Programmer's Guide 10g Release 2 (10.2) Part Number B14252-01 |
Home | Book List | Contents | Index | Master Index | Feedback

Previous | Next
| View PDF

# 15 Using the XML Parser for C

This chapter contains these topics:

- Introduction to the XML Parser for C

- Using the XML Parser for C

- Using the DOM API for C

- Using the SAX API for C

- Using OCI and the XDK C API

## Introduction to the XML Parser for C

This section contains the following topics:

- Prerequisites

- Standards and Specifications

See Also: "Introduction to the XML Parser for Java" for a generic introduction to XML parsing with DOM and SAX. Much of the information in the introduction is language-independent and applies equally to C.

### Prerequisites

The Oracle XML parser for C reads an XML document and uses DOM or SAX APIs to provide programmatic access to its content and structure. You can use the parser in validating or nonvalidating mode.

This chapter assumes that you are familiar with the following technologies:

- Document Object Model (DOM). DOM is an in-memory tree representation of the structure of an XML document.

- Simple API for XML (SAX). SAX is a standard for event-based XML parsing.

- Document Type Definition (DTD). An XML DTD defines the legal structure of an XML document.

- XML Schema. Like a DTD, an XML schema defines the legal structure of an XML document.

- XML Namespaces. Namespaces are a mechanism for differentiating element and attribute names.

If you require a general introduction to the preceding technologies, consult the XML resources listed in "Related Documents" of the preface.

### Standards and Specifications

XML 1.0 is a W3C Recommendation. The C XDK API provides full support for XML 1.0 (Second Edition). You can find the specification for the Second Edition at the following URL:

    http://www.w3.org/TR/2000/REC-xml-20001006

The DOM Level 1, Level 2, and Level 3 specifications are W3C Recommendations. The C XDK API provides full suport for DOM Level 1 and 2, but no support for Level 3. You can find links to the specifications for all three levels at the following URL:

    http://www.w3.org/DOM/DOMTR

SAX is available in version 1.0, which is deprecated, and 2.0. SAX is not a W3C specification. The C XDK API provides full support for both SAX 1.0 and 2.0. You can find the documentation for SAX at the following URL:

    http://www.saxproject.org

XML Namespaces are a W3C Recommendation. You can find the specification at the following URL:

    http://www.w3.org/TR/REC-xml-names

See Also: Chapter 29, "XDK Standards" for a summary of the standards supported by the XDK

## Using the XML Parser for C

Oracle XML parser for C checks if an XML document is well-formed, and optionally validates it against a DTD. Your application can access the parsed data through the DOM or SAX APIs.

This section contains the following topics:

- Overview of the Parser API for C

- Using the XML Parser for C: Basic Process

- Running the XML Parser for C Demo Programs

- Using the C XML Parser Command-Line Utility

### Overview of the Parser API for C

The core of the XML parsing API are the XML, DOM, and SAX APIs. Table 15-1 describes the interfaces for these APIs. Refer to Oracle XML API Reference for the complete API documentation.

Table 15-1 Interfaces for XML, DOM, and SAX APIs

Package | Interfaces | Function Name Convention
--- | --- | ---
XML | This package implements a single `XML` interface. The interface defines functions for the following tasks: Creating and destroying contexts. A top-level XML context (`xmlctx`) shares common information between cooperating XML components. Creating and parsing XML documents and DTDs. | Function names begin with the string `Xml`. Refer to Oracle Database XML C API Reference for API documentation.
DOM | This package provides programmatic access to parsed XML. The package implements the following interfaces: `Attr` defines get and set functions for XML attributes. `CharacterData` defines functions for manipulating character data. `Document` defines functions for creating XML nodes, obtaining information about an XML document, and setting the DTD for a document. `DocumentType` defines get functions for DTDs. `Element` defines get and set functions for XML elements. `Entity` defines get functions for XML entities. `NamedNodeMap` defines get functions for named nodes. `Node` defines get and set functions for XML nodes. `NodeList` defines functions that free a node list and get a node from a list. `Notation` defines functions that get the system and public ID from a node. `ProcessingInstruction` defines get and set functions for processing instructions. `Text` defines a function that splits a text node into two. | Function names begin with the string `XmlDom`. Refer to Oracle Database XML C API Reference for API documentation.
SAX | This package provides programmatic access to parsed XML. The package implements the `SAX` interface, which defines functions that receive notifications for SAX events. | Function names begin with the string `XmlSax`. Refer to Oracle Database XML C API Reference for API documentation.

#### XML Parser for C Datatypes

Refer to Oracle XML API Reference for the complete list of datatypes for the C XDK. Table 15-2 describes the datatypes used in the XML parser for C.

Table 15-2 Datatypes Used in the XML Parser for C

Datatype | Description
--- | ---
`oratext` | String pointer
`xmlctx` | Master XML context
`xmlsaxcb` | SAX callback structure (SAX only)
`ub4` | 32-bit (or larger) unsigned integer
`uword` | Native unsigned integer

#### XML Parser for C Defaults

Note the following defaults for the XML parser for C:

- Character set encoding is UTF-8. If all your documents are ASCII, then setting the encoding to US-ASCII increases performance.

- The parser prints messages to `stderr` unless an error handler is provided.

- The parser checks inputs documents for well-formedness but not validity. You can set the property "validate" to validate the input.

  Note: It is recommended that you set the default encoding explicitly if using only single byte character sets (such as US-ASCII or any of the ISO-8859 character sets) for faster performance than is possible with multibyte character sets such as UTF-8.

- The parser conforms to the XML 1.0 specification when processing whitespace, that is, the parser reports all whitespace to the application but indicates which whitespace can be ignored. However, some applications may prefer to set the property "discard-whitespace," which discards all whitespace between an end-element tag and the following start-element tag.

See Also: Oracle Database XML C API Reference for the DOM, SAX, and callback APIs `http://www.oracle.com/technology/tech/xml/`

### Using the XML Parser for C: Basic Process

Figure 15-1 illustrates the calling sequence for the XML parser for C.

Figure 15-1 XML Parser for C Calling Sequence

Description of the illustration adxdk096.gif

Perform the following steps in your application:

1. Initialize the parsing process with the `XmlCreate()` function. The following sample code fragment is from `DOMNamespace.c`:

       xmlctx     *xctx;
       ...
       xctx = XmlCreate(&ecode, (oratext *) "namespace_xctx", NULL);

2. Parse the input item, which can be an XML document or string buffer

   If you are parsing with DOM, call the `XmlLoadDom()` function. The following sample code fragment is from `DOMNamespace.c`:

       xmldocnode *doc;
       ...
       doc = XmlLoadDom(xctx, &ecode, "file", DOCUMENT,
                        "validate", TRUE, "discard_whitespace", TRUE, NULL);

   If you are parsing with SAX, call the `XmlLoadSax()` function. The following sample code fragment is from `SAXNamespace.c`:

       xmlerr      ecode;
       ...
       ecode = XmlLoadSax(xctx, &sax_callback, &sc, "file", DOCUMENT,
                              "validate", TRUE, "discard_whitespace", TRUE, NULL);

3. If you are using the DOM interface, then include the following steps:

   - Use the `XmlLoadDom()` function to call `XmlDomGetDocElem()`. This step calls other DOM functions, which are typically node or print functions that output the DOM document, as required. The following sample code fragment is from `DOMNamespace.c`:

         printElements(xctx, XmlDomGetDocElem(xctx, doc));

   - Invoke the `XmlFreeDocument()` function to clean up any data structures created during the parse process. The following sample code fragment is from `DOMNamespace.c`:

         XmlFreeDocument(xctx, doc);

   If you are using the SAX interface, then include the following steps:

   - Process the results of the invocation of `XmlLoadSax()` with callback functions.

   - Register the callback functions. Note that you can set any of the SAX callback functions to `NULL` if not needed.

4. Use `XmlFreeDocument()` to clean up the memory and structures used during a parse. The program does not free memory allocated for parameters passed to the SAX callbacks or for nodes and data stored with the DOM parse tree until you call `XMLFreeDocument()` or `XMLDestroy()`. The following sample code fragment is from `DOMNamespace.c`:

       XmlFreeDocument(xctx, doc);

   Either return to Step 2 or proceed to the next step.

5. Terminate the parsing process with `XmlDestroy()`. The following sample code fragment is from `DOMNamespace.c`:

       (void) XmlDestroy(xctx);

   If threads fork off somewhere in the sequence of calls between initialization and termination, the application produces unpredictable behavior and results.

You can use the memory callback functions `XML_ALLOC_F` and `XML_FREE_F` for your own memory allocation. If you do, then specify both functions.

### Running the XML Parser for C Demo Programs

The `$ORACLE_HOME/xdk/demo/c/` (UNIX) and `%ORACLE_HOME%\xdk\demo\c` (Windows) directories include several XML applications that illustrate how to use the XML parser for C with the DOM and SAX interfaces. Table 15-3 describes the demos.

Table 15-3 C Parser Demos

Directory | Contents | Demos
--- | --- | ---
`dom` |
    DOMNamespace.c
    DOMSample.c
    FullDom.c
    FullDom.xml
    NSExample.xml
    Traverse.c
    XPointer.c
    class.xml
    cleo.xml
    pantry.xml
| The `make` utility compiles source files `name.c` to produce demo program `name` and output file `name.out` . The `name.std` is the expected output. The following demo programs use the DOM API: The `DOMNamespace` program uses Namespace extensions to the DOM API. It prints out all elements and attributes of `NSExample.xml` along with full namespace information. The `DOMSample` program uses DOM APIs to display an outline of Cleopatra, that is, the XML elements `ACT` and `SCENE`. The `cleo.xml` document contains the XML version of Shakespeare's The Tragedy of Antony and Cleopatra. The `FullDom` program shows sample usage of the full DOM interface. It exercises all the calls. The program accepts `FullDom.xml`, which shows the use of entities, as input. The `Traverse` program illustrates the use of DOM iterators, tree walkers, and ranges. The program accepts the `class.xml` document, which describes a college Calculus course, as input. The `XPointer` program illustrates the use of the XML Pointer Language by locating the children of the `<pantry>` element in `pantry.xml`.
`sax` |
    NSExample.xml
    SAXNamespace.c
    SAXSample.c
    cleo.xml
| The `make` utility compiles source files `name.c` to produce demo program `name` and output file `name.out` . The `name.std` is the expected output. The following demo programs use the SAX APIs: The `SAXNamespace` program uses namespace extensions to the SAX API. It prints out all elements and attributes of `NSExample.xml` along with full namespace information. The `SAXSample` program uses SAX APIs to show all lines in the play Cleopatra containing a given word. If you do not specify a word, then it uses the word "death." The `cleo.xml` document contains the XML version of Shakespeare's The Tragedy of Antony and Cleopatra.

You can find documentation that describes how to compile and run the sample programs in the `README` in the same directory. The basic steps are as follows:

1. Change into the `$ORACLE_HOME/xdk/demo/c` directory (UNIX) or `%ORACLE_HOME%\xdk\demo\c` directory (Windows).

2. Make sure that your environment variables are set as described in "Setting C XDK Environment Variables on UNIX" and "Setting C XDK Environment Variables on Windows".

3. Run `make` (UNIX) or `Make.bat` (Windows) at the system prompt. The `make` utility changes into each demo subdirectory and runs `make` to do the following:

   1. Compiles the C source files with the `cc` utility. For example, the `Makefile` in the `$ORACLE_HOME/xdk/demo/c/dom` directory includes the following line:

          $(CC) -o DOMSample $(INCLUDE) $@.c $(LIB)

   2. Runs each demo program and redirects the output to a file. For example, the `Makefile` in the `$ORACLE_HOME/xdk/demo/c/dom` directory includes the following line:

          ./DOMSample > DOMSample.out

4. Compare the `*.std` files to the `*.out` files for each program. The `*.std` file contains the expected output for each program. For example, `DOMSample.std` contains the expected output from running `DOMSample`.

### Using the C XML Parser Command-Line Utility

The `xml` utility, which is located in `$ORACLE_HOME/bin` (UNIX) or `%ORACLE_HOME%\bin` (Windows), is a command-line interface that parses XML documents. It checks for both well-formedness and validity.

To use `xml` ensure that your environment is set up as described in "Setting C XDK Environment Variables on UNIX" and "Setting C XDK Environment Variables on Windows".

Use the following syntax on the command line to invoke `xml` (the Windows version is `xml.exe`):

    xml [options] [document URI]
    xml -f [options] [document filespec]

Table 15-4 describes the command-line options.

Table 15-4 C Parser Command-Line Options

Option | Description
--- | ---
`-B` BaseURI | Sets the base URI for the XSLT processor. The base URI of `http://pqr/xsl.txt` resolves `pqr.txt` to `http://pqr/pqr.txt`.
`-c` | Checks well-formedness, but performs no validation.
`-e` `encoding` | Specifies default input file encoding ("incoding").
`-E` `encoding` | Specifies DOM/SAX encoding ("outcoding").
`-f` `file` | Interprets the file as filespec, not URI.
`-G` `xptr_exprs` | Evaluates XPointer scheme examples given in a file.
`-h` | Shows usage help and basic list of command-line options.
`-hh` | Shows complete list command-line options.
`-i` `n` | Specifies the number of times to iterate the XSLT processing.
`-l` `language` | Specifies the language for error reporting.
`-n` | Traverses the DOM and reports the number of elements, as shown in the following sample output:
    ELEMENT       1
     PCDATA       1
        DOC       1
      TOTAL       3 * 60 = 180
`-o` `XSLoutfile` | Specifies the output file of the XSLT processor.
`-p` | Prints the document/DTD structures after the parse. For example, the root element `<greeting>hello</greeting>` is printed as:
    +---ELEMENT greeting     +---PCDATA "hello"
`-P` | Prints the document from the root element. For example, the root element `<greeting>hello</greeting>` is printed as:
    <greeting>hello</greeting>
`-PP` | Prints from the root node (DOC) and includes the XML declaration.
`-PE encoding` | Specifies the encoding for `-P` or `-PP` output.
`-PX` | Includes the XML declaration in the output.
`-s` `stylesheet` | Specifies the XSLT stylesheet.
`-v` | Displays the XDK parser version and then exits.
`-V` `var value` | Tests top-level variables in CXSLT.
`-w` | Preserves all whitespace.
`-W` | Stops parsing after a warning.
`-x` | Exercises the SAX interface and prints the document, as shown in the following sample output:
    StartDocumentXMLDECL version='1.0' encoding=FALSE<greeting>    "hello"</greeting>EndDocument

#### Using the XML Parser Command-Line Utility: Example

You can test `xml` on the various XML files located in `$ORACLE_HOME/xdk/demo/c`. Example 15-1 displays the contents of `NSExample.xml`.

Example 15-1 NSExample.xml

    <!DOCTYPE doc [
    <!ELEMENT doc (child*)>
    <!ATTLIST doc xmlns:nsprefix CDATA #IMPLIED>
    <!ATTLIST doc xmlns CDATA #IMPLIED>
    <!ATTLIST doc nsprefix:a1 CDATA #IMPLIED>
    <!ELEMENT child (#PCDATA)>
    ]>
    <doc nsprefix:a1 = "v1" xmlns="http://www.w3c.org"
         xmlns:nsprefix="http://www.oracle.com">
    <child>
    This element inherits the default Namespace of doc.
    </child>
    </doc>

You can parse this file, count the number of elements, and display the DOM tree as shown in the following example:

    xml -np class.xml > xml.out

The output is shown in the next example.

Example 15-2 xml.out

    ELEMENT       2
        PCDATA       1
           DOC       1
           DTD       1
      ELEMDECL       2
      ATTRDECL       3
         TOTAL      10 * 112 = 1120
    +---ELEMENT doc [nsprefix:a1='v1'*, xmlns='http://www.w3c.org'*, xmlns:nsprefix=
    'http://www.oracle.com'*]
        +---ELEMENT child
            +---PCDATA "
    This element inherits the default Namespace of doc.
    "

## Using the DOM API for C

This section contains the following topics:

- Creating the Top-Level Context

- Controlling the Data Encoding of XML Documents for the C API

- Using NULL-Terminated and Length-Encoded C API Functions

- Handling Errors with the C API

### Creating the Top-Level Context

When using the DOM to process XML in a traditional file system or on the Web, you need to perform implementation-specific steps only for startup.

Your application requires a top-level `xmlctx`. This context contains encoding information, low-level memory callbacks, error message language, encoding, and so on. In short, this context contains those things that should remain consistent for all XDK components. The basic steps for initialization are as follows:

1. Allocate an `xmlctx` with `XmlCreate()`. For example:

       xmlctx *xctx;
       xmlerr  err;

       xctx = (xmlctx *) XmlCreate(&err, "xdk context", "data-encoding",
                                   "ascii", ..., NULL);

2. Load documents and generate DOM events. After the application obtains an `xmlctx`, it can load a serialized XML document with the `XmlLoadDom()` or `XmlLoadSax()` functions. Given the Document node, all API DOM functions are available. You can generate DOM as in the following example:

       xmldocnode *domctx;
       xmlerr err;

       domctx = XmlLoadDom(xctx, &err, "file", "some_file.xml", NULL);

   To generate SAX events, you need a SAX callback structure as shown in the following example:

       xmlsaxcb saxcb = {
         UserAttrDeclNotify,  /* user's own callback functions */
         UserCDATANotify,
         /* ... */
       };

       if (XmlLoadSax(xctx, &saxcb, NULL, "file", "some_file.xml", NULL) != 0)
         /* an error occured */

3. You can tear down the XML context with the `XmlDestroy()` function.

### Controlling the Data Encoding of XML Documents for the C API

XML data occurs in many encodings. You can control the XML encoding in the following ways:

- Specify a default encoding to assume for files that are not self-describing

- Specify the presentation encoding for DOM or SAX

- Re-encode when a DOM is serialized

Input XML data is always encoded. Some encodings are entirely self-describing, such as UTF-16, which requires a specific BOM before the start of the actual data. The `XMLDecl` or MIME header of the document can also specify an encoding. If the application cannot determine the specific encoding, then it applies the default input encoding. If you do not provide a default, then the application assumes UTF-8 on ASCII platforms and UTF-E on EBCDIC platforms.

The API makes a provision for cases when the encoding data of the input document is corrupt. For example, suppose an ASCII document with an `XMLDecl` of `encoding=ascii` is blindly converted to EBCDIC. The new EBCDIC document contains (in EBCDIC) an `XMLDecl` that incorrectly claims the document is ASCII. The correct behavior for a program that is re-encoding XML data is to regenerate but not convert the `XMLDecl`. The `XMLDecl` is metadata, not data itself. This rule is often ignored, however, which results in corrupt documents. To work around this problem, the API provides an additional flag that enables you to forcibly set the input encoding, thereby overcoming an incorrect `XMLDecl`.

The precedence rules for determining input encoding are as follows:

1. Forced encoding as specified by the user

   Caution: Forced encoding can result in a fatal error if there is a conflict. For example, the input document is UTF-16 and starts with a UTF-16 BOM, but the user specifies a forced UTF-8 encoding. In this case, the parser will object about the conflict.

2. Protocol specification (HTTP header, and so on)

3. `XMLDecl` specification

4. User's default input encoding

5. The default, which is UTF-8 on ASCII platforms or UTF-E on EBCDIC platforms

After the application has determined the input encoding has been determined, it can parse the document and present the data. You are allowed to choose the presentation encoding; the data will be in that encoding regardless of the original input encoding.

When an application writes back a DOM in serialized form, it can choose at that time to re-encode the presentation data. Thus, the you can place the serialized document in any encoding.

### Using NULL-Terminated and Length-Encoded C API Functions

The native string representation in C is NULL-terminated. Thus, the primary DOM interface takes and returns NULL-terminated strings. When stored in table form, however, Oracle XML DB data is not NULL-terminated but length-encoded. Consequently, the XDK provides an additional set of length-encoded APIs for the high-frequency cases to improve performance. In particular, the DOM functions in Table 15-5 have dual APIs.

Table 15-5 NULL-Terminated and Length-Encoded C API Functions

NULL-Terminated API | Length-Encoded API
--- | ---
`XmlDomGetNodeName()` | `XmlDomGetNodeNameLen()`
`XmlDomGetNodeLocal()` | `XmlDomGetNodeLocalLen()`
`XmlDomGetNodeURI()` | `XmlDomGetNodeURILen()`
`XmlDomGetNodeValue()` | `XmlDomGetNodeValueLen()`
`XmlDomGetAttrName()` | `XmlDomGetAttrNameLen()`
`XmlDomGetAttrLocal()` | `XmlDomGetAttrLocalLen()`
`XmlDomGetAttrURI()` | `XmlDomGetAttrURILen()`
`XmlDomGetAttrValue()` | `XmlDomGetAttrValueLen()`

### Handling Errors with the C API

The C API functions typically either return a numeric error code (0 for success, nonzero on failure), or pass back an error code through a variable. In all cases, the API stores error codes. Your application can retrieve the most recent error by calling the `XmlDomGetLastError()` function.

By default, the API outputs error messages to `stderr`. However, you can register an error message callback at initialization time. When an error occurs, the application invokes the registered callback and does not print an error.

## Using the SAX API for C

To use SAX, initialize an `xmlsaxcb` structure with function pointers and pass it to the `XmlLoadSax()` call. You can also include a pointer to a user-defined context structure, which you pass to each SAX function.

See Also: Oracle Database XML C API Reference for the SAX callback structure

## Using OCI and the XDK C API

This section contains the following topics:

- Using XMLType Functions and Descriptions

- Initializing an XML Context

- Creating XMLType Instances on the Client

- Operating on XML Data in the Database Server

- Using OCI and the XDK C API: Examples

### Using XMLType Functions and Descriptions

You can use the C API for XML for `XMLType` columns in the database. An Oracle Call Interface (OCI) program can access XML data stored in a table by initializing the values of OCI handles such as the following:

- Environment handle

- Service handle

- Error handle

- Optional parameters

The program can pass these input values to the function `OCIXmlDbInitXmlCtx()`, which returns an XML context. After the program makes calls to the C API, the function `OCIXmlDbFreeXmlCtx()` frees the context.

Table 15-6 describes a few of the functions for XML operations.

Table 15-6 XMLType Functions

Function Name | Description
--- | ---
`XmlCreateDocument()` | Create empty `XMLType` instance
`XmlLoadDom()` and so on | Create from a source buffer
`XmlXPathEvalexpr()` and family | Extract an `XPath` expression
`XmlXslProcess()` and family | Transform using an XSLT stylesheet
`XmlXPathEvalexpr()` and family | Check if an `XPath` exists
`XmlDomIsSchemaBased()` | Is document schema-based?
`XmlDomGetSchema()` | Get schema information
`XmlDomGetNodeURI()` | Get document namespace
`XmlSchemaValidate()` | Validate using schema
Cast `(void *)` to `(xmldocnode *)` | Obtain DOM from `XMLType`
Cast `(xmldocnode *)` to `(void *)` | Obtain `XMLType` from DOM

### Initializing an XML Context

An XML context is a required parameter in all the C DOM API functions. This opaque context encapsulates information pertaining to data encoding, error message language, and so on. The contents of this XML context are different for XDK applications and for Oracle XML DB applications.

Caution: Do not use an XML context for XDK in an XML DB application, or an XML context for XML DB in an XDK application.

For Oracle XML DB, the two OCI functions that initialize and free an XML context have the following prototypes:

    xmlctx *OCIXmlDbInitXmlCtx (OCIEnv *envhp, OCISvcCtx *svchp, OCIError *errhp,
           ocixmldbparam *params, ub4 num_params);

    void OCIXmlDbFreeXmlCtx (xmlctx *xctx);

See Also: Oracle Call Interface Programmer's Guide for reference material on the functions. Oracle Call Interface Programmer's Guide for a discussion about OCI support for XML. Oracle Database XML C API Reference for reference information on the DOM APIs

### Creating XMLType Instances on the Client

You can construct new `XMLType` instances on the client by using the `XmlLoadDom()` calls. Follow these basic steps:

1. You first have to initialize the `xmlctx`, as illustrated in the example in "Using the DOM API for C".

2. You can construct the XML data itself from the following sources:

   - User buffer

   - Local file

   - URI

   The return value from these is an `(xmldocnode *)`, which you can use in the rest of the common C API.

3. Finally, you can cast the `(xmldocnode *)` to a (`void *)` and directly provide it as the bind value if required.

You can construct empty `XMLType` instances by using the `XmlCreateDocument()` call. This function would be equivalent to an `OCIObjectNew()` for other types. You can operate on the `(xmldocnode *)` returned by the preceding call and finally cast it to a `(void *)` if it needs to be provided as a bind value.

### Operating on XML Data in the Database Server

You can operate on XML data in Oracle Database by means of OCI statement calls. You can bind and define `XMLType` values using `xmldocnode` and use OCI statements to select XML data from the database. You can use this data directly in the C DOM functions. Similarly, you can bind the values directly to SQL statements.

### Using OCI and the XDK C API: Examples

Example 15-3 illustrates how to construct a schema-based document with the DOM API and save it to the database. Note that you must include the header files `xml.h` and `ocixmldb.h`.

Example 15-3 Constructing a Schema-Based Document with the DOM API

    #include <xml.h>
    #include <ocixmldb.h>
    static oratext tlpxml_test_sch[] = "<TOP xmlns='example1.xsd'\n\
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' \n\
    xsi:schemaLocation='example1.xsd example1.xsd'/>";

    void example1()
    {
        OCIEnv *envhp;
        OCIError *errhp;
        OCISvcCtx *svchp;
        OCIStmt *stmthp;
        OCIDuration dur;
        OCIType *xmltdo;

        xmldocnode  *doc;
        ocixmldbparam params[1];
        xmlnode *quux, *foo, *foo_data;
        xmlerr       err;

        /* Initialize envhp, svchp, errhp, dur, stmthp */
        /* ........ */

        /* Get an xml context */
        params[0].name_ocixmldbparam = XCTXINIT_OCIDUR;
        params[0].value_ocixmldbparam = &dur;
        xctx = OCIXmlDbInitXmlCtx(envhp, svchp, errhp, params, 1);

        /* Start processing */
        printf("Supports XML 1.0: %s\n",
           XmlHasFeature(xctx, (oratext *) "xml", (oratext *) "1.0") ?
                         "YES" : "NO");

        /* Parsing a schema-based document */
        if (!(doc = XmlLoadDom(xctx, &err, "buffer", tlpxml_test_sch,
                              "buffer_length", sizeof(tlpxml_test_sch)-1,
                              "validate", TRUE, NULL)))
        {
           printf("Parse failed, code %d\n");
           return;
        }

        /* Create some elements and add them to the document */
        top = XmlDomGetDocElem(xctx, doc);
        quux = (xmlnode *) XmlDomCreateElem(xctx ,doc, (oratext *) "QUUX");
        foo = (xmlnode *) XmlDomCreateElem(xctx, doc, (oratext *) "FOO");
        foo_data = (xmlnode *) XmlDomCreateText(xctx, doc, (oratext *)"foo's data");
        foo_data = XmlDomAppendChild(xctx, (xmlnode *) foo, (xmlnode *) foo_data);
        foo = XmlDomAppendChild(xctx, quux, foo);
        quux = XmlDomAppendChild(xctx, top, quux);

        XmlSaveDom(xctx, &err, top, "stdio", stdout, NULL);
        XmlSaveDom(xctx, &err, doc, "stdio", stdout, NULL);

        /* Insert the document to my_table */
        ins_stmt = "insert into my_table values (:1)";

        status = OCITypeByName(envhp, errhp, svchp, (const text *) "SYS",
                       (ub4) strlen((char *)"SYS"), (const text *) "XMLTYPE",
                       (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0,
                       (ub4) 0, dur, OCI_TYPEGET_HEADER,
                       (OCIType **) &xmltdo)) ;

        if (status == OCI_SUCCESS)
        {
           exec_bind_xml(svchp, errhp, stmthp, (void *)doc, xmltdo, ins_stmt));
        }

       /* free xml ctx */
       OCIXmlDbFreeXmlCtx(xctx);
    }

    /*--------------------------------------------------------*/
    /* execute a sql statement which binds xml data */
    /*--------------------------------------------------------*/
    sword exec_bind_xml(svchp, errhp, stmthp, xml, xmltdo, sqlstmt)
    OCISvcCtx *svchp;
    OCIError *errhp;
    OCIStmt *stmthp;
    void *xml;
    OCIType *xmltdo;
    OraText *sqlstmt;
    {
       OCIBind *bndhp1 = (OCIBind *) 0;
       OCIBind *bndhp2 = (OCIBind *) 0;
       sword  status = 0;
       OCIInd ind = OCI_IND_NOTNULL;
       OCIInd *indp = &ind;

       if(status = OCIStmtPrepare(stmthp, errhp, (OraText *)sqlstmt,
                        (ub4)strlen((char *)sqlstmt),
                        (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) {
         return OCI_ERROR;
       }

       if(status = OCIBindByPos(stmthp, &bndhp1, errhp, (ub4) 1, (dvoid *) 0,
                       (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0,
                       (ub2 *)0, (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) {
         return OCI_ERROR;
       }

       if(status = OCIBindObject(bndhp1, errhp, (CONST OCIType *) xmltdo,
                   (dvoid **) &xml, (ub4 *) 0, (dvoid **) &indp, (ub4 *) 0)) {
         return OCI_ERROR;
       }

       if(status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                    (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT)) {
         return OCI_ERROR;
      }

       return OCI_SUCCESS;
    }

Example 15-4 illustrates how to get a document from the database and modify it with the DOM API.

Example 15-4 Modifying a Database Document with the DOM API

    #include <xml.h>
    #include <ocixmldb.h>
    sword example2()
    {
        OCIEnv *envhp;
        OCIError *errhp;
        OCISvcCtx *svchp;
        OCIStmt *stmthp;
        OCIDuration dur;
        OCIType *xmltdo;

        xmldocnode  *doc;
        xmlnodelist *item_list; ub4 ilist_l;
        ocixmldbparam params[1];
        text *sel_xml_stmt = (text *)"SELECT xml_col FROM my_table";
        ub4    xmlsize = 0;
        sword  status = 0;
        OCIDefine *defnp = (OCIDefine *) 0;

        /* Initialize envhp, svchp, errhp, dur, stmthp */
        /* ........ */

        /* Get an xml context */
        params[0].name_ocixmldbparam = XCTXINIT_OCIDUR;
        params[0].value_ocixmldbparam = &dur;
        xctx = OCIXmlDbInitXmlCtx(envhp, svchp, errhp, params, 1);

        /* Start processing */
        if(status = OCITypeByName(envhp, errhp, svchp, (const text *) "SYS",
                       (ub4) strlen((char *)"SYS"), (const text *) "XMLTYPE",
                       (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0,
                       (ub4) 0, dur, OCI_TYPEGET_HEADER,
                       (OCIType **) xmltdo_p)) {
           return OCI_ERROR;
        }

        if(!(*xmltdo_p)) {
           printf("NULL tdo returned\n");
           return OCI_ERROR;
        }

        if(status = OCIStmtPrepare(stmthp, errhp, (OraText *)selstmt,
                        (ub4)strlen((char *)selstmt),
                        (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) {
          return OCI_ERROR;
        }

        if(status = OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, (dvoid *) 0,
                       (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0,
                       (ub2 *)0, (ub4) OCI_DEFAULT)) {
           return OCI_ERROR;
        }

        if(status = OCIDefineObject(defnp, errhp, (OCIType *) *xmltdo_p,
                                (dvoid **) &doc,
                                &xmlsize, (dvoid **) 0, (ub4 *) 0)) {
          return OCI_ERROR;
        }

        if(status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                     (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT)) {
          return OCI_ERROR;
        }

        /* We have the doc. Now we can operate on it */
        printf("Getting Item list...\n");

       item_list = XmlDomGetElemsByTag(xctx,(xmlelemnode *) elem,(oratext *)"Item");
        ilist_l   = XmlDomGetNodeListLength(xctx, item_list);
        printf(" Item list length = %d \n", ilist_l);

        for (i = 0; i < ilist_l; i++)
        {
          elem = XmlDomGetNodeListItem(xctx, item_list, i);
          printf("Elem Name:%s\n", XmlDomGetNodeName(xctx, fragelem));
          XmlDomRemoveChild(xctx, fragelem);
        }

        XmlSaveDom(xctx, &err, doc, "stdio", stdout, NULL);

       /* free xml ctx */
       OCIXmlDbFreeXmlCtx(xctx);

       return OCI_SUCCESS;
    }